home *** CD-ROM | disk | FTP | other *** search
/ SGI Developer Toolbox 6.1 / SGI Developer Toolbox 6.1 - Disc 4.iso / src / apps / gmemusage / inode.c < prev    next >
C/C++ Source or Header  |  1994-08-01  |  9KB  |  437 lines

  1. /*
  2.  * inode.c
  3.  *
  4.  * Stuff for translating (dev,inode) pairs to file names
  5.  *
  6.  * Stolen from memusage programs
  7.  *
  8.  * Copyright 1994, Silicon Graphics, Inc.
  9.  * All Rights Reserved.
  10.  *
  11.  * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics, Inc.;
  12.  * the contents of this file may not be disclosed to third parties, copied or
  13.  * duplicated in any form, in whole or in part, without the prior written
  14.  * permission of Silicon Graphics, Inc.
  15.  *
  16.  * RESTRICTED RIGHTS LEGEND:
  17.  * Use, duplication or disclosure by the Government is subject to restrictions
  18.  * as set forth in subdivision (c)(1)(ii) of the Rights in Technical Data
  19.  * and Computer Software clause at DFARS 252.227-7013, and/or in similar or
  20.  * successor clauses in the FAR, DOD or NASA FAR Supplement. Unpublished -
  21.  * rights reserved under the Copyright Laws of the United States.
  22.  */
  23.  
  24. #include <sys/types.h>
  25. #include <sys/stat.h>
  26. #include <sys/param.h>
  27.  
  28. #include <stdio.h>
  29. #include <unistd.h>
  30. #include <fcntl.h>
  31. #include <string.h>
  32. #include <stdlib.h>
  33.  
  34. #include "process.h"
  35. #include "draw.h"
  36.  
  37. #define INODEFILE ".gmemusage.inodes"
  38. #define INODEFILETMP ".gmemusage.inodes.tmp"
  39. #define DEFUSAGEPATH \
  40.     "/usr/ToolTalk:/usr/bin:/usr/lib:/usr/local:/usr/Cadmin:"\
  41.     "/usr/CaseVision:/usr/sbin:/usr/bsd:/usr/etc:/lib:"\
  42.     "/sbin:/bin:/etc:/usr/gfx "
  43. #define PATHSEP ";,: "
  44. #define FINDCMD "find "
  45. #define FINDARGS "-type f \\( -perm -0100 -o -name \\*so\\* \\) -print "
  46. #define FINDMUNGE " | xargs /sbin/ls -lLid | " \
  47.     "sed -e /fonts/d -e /terminfo/d | " \
  48.     "awk '{printf \"%d %s\\n\", $1, $10 }'  "\
  49.     ";"\
  50.     "echo "\
  51.     "/dev/zero "\
  52.     "| xargs /sbin/ls -lLid | "\
  53.     "awk '{printf \"%d %s\\n\", $1, $11 }'"
  54.     
  55.  
  56. struct inrec {
  57.     struct inrec *next;
  58.     long inode;
  59.     dev_t rdev;
  60.     char *name;
  61. };
  62.  
  63. static struct inrec *inodes;
  64. static char *inodePath = NULL;
  65. static char *inodePathTmp = NULL;
  66.  
  67. static void
  68. MakePaths(void)
  69. {
  70.     char *home;
  71.  
  72.     if (!inodePath) {
  73.     home = getenv("HOME");
  74.     if (!home) {
  75.         home = "/var/tmp";
  76.     }
  77.     /*
  78.      * 2 == 1 ('/') + 1 ('\0')
  79.      */
  80.     inodePath = malloc(strlen(home) + strlen(INODEFILE) + 2);
  81.     sprintf(inodePath, "%s/%s", home, INODEFILE);
  82.     inodePathTmp = malloc(strlen(home) + strlen(INODEFILETMP) + 2);
  83.     sprintf(inodePathTmp, "%s/%s", home, INODEFILETMP);
  84.     }
  85. }
  86.  
  87. /*
  88.  *  static char *
  89.  *  basename(char *path)
  90.  *
  91.  *  Description:
  92.  *      Get the base file name of a path.  Local so I don't have to
  93.  *      suck in libgen just for this one trivial fuction.
  94.  *
  95.  *  Parameters:
  96.  *      path
  97.  *
  98.  *  Returns:
  99.  *      Pointer to basename of path (not duplicated!)
  100.  */
  101.  
  102. static char *
  103. basename(char *path)
  104. {
  105.     char *slash;
  106.  
  107.     slash = strrchr(path, '/');
  108.  
  109.     return slash ? slash + 1 : path;
  110. }
  111.  
  112. static dev_t
  113. easy_stat (char *path)
  114. {
  115.     struct stat statbuf;
  116.     if (stat (path, &statbuf) != 0)
  117.         return -1;
  118.     return statbuf.st_dev;
  119. }
  120.  
  121. static dev_t
  122. get_device (char *path)
  123. {
  124.     struct stat    st;
  125.     char buff[MAXPATHLEN + 12], str[MAXPATHLEN], buf[256];
  126.     FILE *fp;
  127.  
  128.     dev_t i;
  129.     if ((i = easy_stat(path)) > 0)
  130.         return i;
  131.  
  132.     sprintf (buff, "/etc/devnm %s", path, getpid());
  133.     
  134.     if ((fp = popen(buff, "r")) == NULL) {
  135.         perror("popen");
  136.         return -1;
  137.     }
  138.     setbuffer(fp, buf, sizeof buf);
  139.  
  140.     fscanf (fp, "%s", str);
  141.     pclose (fp);
  142.  
  143.     if (strcmp (str, "devnm:") == 0) {
  144.         return (-1);
  145.     }
  146.     if (strncmp (str, "/dev/", 5) != 0 &&
  147.         strchr (str, ':') == NULL) {
  148.         strcpy (buff, "/dev/");
  149.     } else {
  150.         strcpy (buff, "");
  151.     }
  152.     strcat (buff, str);
  153.  
  154.     if (lstat (buff, &st) == 0 &&
  155.         (st.st_mode & S_IFMT) == S_IFBLK) {
  156.         return (st.st_rdev);
  157.     } else {
  158.         perror ("get_device: lstat");
  159.         return (-1);
  160.     }
  161. }
  162.  
  163. /*
  164.  *  static int
  165.  *  BuildInodeTable(void)
  166.  *
  167.  *  Description:
  168.  *      Find a whole bunch of files, and get their inode numbers
  169.  *
  170.  *  Returns:
  171.  *      0 if successful, -1 if error
  172.  */
  173.  
  174. static int
  175. BuildInodeTable(void)
  176. {
  177.     dev_t ndev;
  178.     FILE *fp, *inodefp;
  179.     long inode;
  180.     char str[256], *findCmd, *usagePath, *dir;
  181.     char buf1[BUFSIZ], buf2[BUFSIZ];
  182.     pid_t pid;
  183.     int errfd;
  184.  
  185.     /*
  186.      * use usagePath as the path to look for executables
  187.      */
  188.     usagePath = getenv("USAGEPATH");
  189.  
  190.     if (!usagePath) {
  191.     usagePath = DEFUSAGEPATH;
  192.     }
  193.  
  194.     /*
  195.      * Dup it because strtok is going to modify it
  196.      */
  197.     usagePath = strdup(usagePath);
  198.  
  199.     findCmd = malloc(strlen(usagePath) + strlen(FINDCMD)
  200.              + strlen(FINDARGS) + strlen(FINDMUNGE) + 1);
  201.  
  202.     strcpy(findCmd, FINDCMD);
  203.  
  204.     for (dir = strtok(usagePath, PATHSEP); dir;
  205.      dir = strtok(NULL, PATHSEP)) {
  206.     strcat(findCmd, dir);
  207.     strcat(findCmd, " ");
  208.     }
  209.  
  210.     strcat(findCmd, FINDARGS);
  211.     strcat(findCmd, FINDMUNGE);
  212.  
  213.     /*
  214.      * Save our stderr for after the find command, and redirect stderr
  215.      * to /dev/null while running find.  This is so that the user
  216.      * doesn't see find's error messages when it can't find things in
  217.      * our list.
  218.      */
  219.     errfd = dup(2);
  220.     close(2);
  221.     (void)open("/dev/null", O_WRONLY);
  222.  
  223.     if ((fp = popen(findCmd, "r")) == NULL) {
  224.     dup2(errfd, 2);
  225.     close(errfd);
  226.     perror("popen");
  227.     return -1;
  228.     }
  229.     setbuffer(fp, buf1, sizeof buf1);
  230.  
  231.     /*
  232.      * Swap euid and uid, so we don't create any files that someone
  233.      * with our uid couldn't create.
  234.      */
  235.     (void)setreuid(geteuid(), getuid());
  236.  
  237.     if ((inodefp = fopen(inodePathTmp, "w")) == NULL) {
  238.     pclose(fp);
  239.     dup2(errfd, 2);
  240.     close(errfd);
  241.     (void)setreuid(geteuid(), getuid());
  242.     perror("fopen");
  243.     return -1;
  244.     }
  245.     setbuffer(fp, buf2, sizeof buf2);
  246.     
  247.     while (fscanf (fp, "%d %s\n", &inode, str) == 2) {
  248.     ndev = get_device (str);
  249.     fprintf (inodefp, "%d %d %s\n", ndev, inode, str);
  250.     }
  251.  
  252.     pclose (fp);
  253.     fclose(inodefp);
  254.  
  255.     /*
  256.      * Restore stderr
  257.      */
  258.     dup2(errfd, 2);
  259.     close(errfd);
  260.  
  261.     /*
  262.      * We don't create the actual database unless all has gone well.
  263.      */
  264.     (void)unlink(inodePath);
  265.     if (link(inodePathTmp, inodePath) == -1) {
  266.     perror("link");
  267.     }
  268.     if (unlink(inodePathTmp) == -1) {
  269.     perror("unlink");
  270.     }
  271.  
  272.     /*
  273.      * Swap back so that we can open everything in /proc
  274.      */
  275.     (void)setreuid(geteuid(), getuid());
  276.     return 0;
  277. }
  278.  
  279. /*
  280.  *  static void
  281.  *  add_inode(long inode, dev_t rdev, char *str)
  282.  *
  283.  *  Description:
  284.  *      Add an inode to the internal list
  285.  *
  286.  *  Parameters:
  287.  *      inode  inode to add
  288.  *      rdev   dev to add
  289.  *      str    name to add
  290.  */
  291.  
  292. static void
  293. add_inode(long inode, dev_t rdev, char *str)
  294. {
  295.     struct inrec *new;
  296.  
  297.     new = (struct inrec *)malloc(sizeof (struct inrec));
  298.     new->next = inodes;
  299.     new->inode = inode;
  300.     new->rdev = rdev;
  301.     new->name = strdup(str);
  302.     /*
  303.      * Be careful!  InodeLookup relies on the fact that the new
  304.      * inode goes at the head of the list; if you change this,
  305.      * make sure to fix InodeLookup.
  306.      */
  307.     inodes = new;
  308. }
  309.  
  310. /*
  311.  * Add dynamic paths into dev/ino map list
  312.  */
  313. static void
  314. prdynpaths(void)
  315. {
  316.     static char *paths[] = { "/var/tmp/.Xshmtrans0",
  317.                  "/tmp/.cadminOSSharedArena",
  318.                  NULL };
  319.     register int i;
  320.     struct stat statd;
  321.  
  322.     /* Add elements to the list */
  323.     for (i = 0; paths[i] != NULL; ++i) {
  324.         if (stat(paths[i], &statd) < 0)
  325.             continue;
  326.         add_inode (statd.st_dev, statd.st_ino, paths[i]);
  327.     }
  328. }
  329.  
  330. /*
  331.  *  int
  332.  *  InodeInit(void)
  333.  *
  334.  *  Description:
  335.  *      Initialize inode table.  If it exists and is newer than /unix,
  336.  *      read it in.  Otherwise, create it.
  337.  *
  338.  *  Returns:
  339.  *      0 if successful, -1 if error
  340.  */
  341.  
  342. int
  343. InodeInit(void)
  344. {
  345.     struct stat stunix, stinodes;
  346.     char str[MAXPATHLEN], buffer[BUFSIZ];
  347.     int rdev, inode;
  348.     FILE *fp;
  349.  
  350.     MakePaths();
  351.  
  352.     if (stat("/unix", &stunix) == -1) {
  353.     perror("/unix");
  354.     return -1;
  355.     }
  356.  
  357.     if (stat(inodePath, &stinodes) == -1 ||
  358.     stunix.st_mtime > stinodes.st_mtime) {
  359.     WaitMessage("Building inode database.  This will take a while,",
  360.             "but only has to be done once.");
  361.     if (BuildInodeTable() == -1) {
  362.         return -1;
  363.     }
  364.     }
  365.  
  366.     if ((fp = fopen(inodePath, "r")) == NULL) {
  367.     perror("fopen");
  368.     return -1;
  369.     }
  370.     setbuffer(fp, buffer, sizeof buffer);
  371.  
  372.     while (fscanf(fp,"%d %d %s\n",&rdev,&inode,str) == 3) {
  373.     add_inode (inode, rdev, basename(str));
  374.     }
  375.  
  376.     fclose(fp);
  377.     prdynpaths();
  378.     return 0;
  379. }
  380.  
  381. /*
  382.  * Given a vnode at address vloc, find a corresponding path name
  383.  */
  384. char *
  385. InodeLookup(int rdev, int inode)
  386. {
  387.     struct inrec *current;
  388.     FILE *fp;
  389.     static char buf[100];
  390.     
  391.     for (current = inodes; current; current = current->next)
  392.     if (current->inode == inode && current->rdev == rdev)
  393.         return current->name;
  394.  
  395.     sprintf(buf, "#%d", inode);
  396.     add_inode(inode, rdev, buf);
  397.     return inodes->name;    /* rely on side effect of add_indode */
  398. }
  399.  
  400. /*
  401.  *  int
  402.  *  FindInode(char *str, dev_t *rdev, ino_t *ino)
  403.  *
  404.  *  Description:
  405.  *      Given a string, find the inode and device number
  406.  *
  407.  *  Parameters:
  408.  *      str   string to find device and inode of
  409.  *      rdev  gets device
  410.  *      ino   gets inode
  411.  *
  412.  *  Returns:
  413.  *      0 if successful, -1 if error
  414.  */
  415.  
  416. int
  417. FindInode(char *str, dev_t *rdev, ino_t *ino)
  418. {
  419.     struct inrec *current;
  420.  
  421.     for (current = inodes; current; current = current->next)
  422.         if (strcmp(current->name, str) == NULL) {
  423.             if (rdev) *rdev = current->rdev;
  424.             if (ino) *ino = current->inode;
  425.             return 0;
  426.         }
  427.     return -1;
  428. }
  429.  
  430. int
  431. InvalidateInodeTable(void)
  432. {
  433.     MakePaths();
  434.     (void)unlink(inodePath);
  435.     (void)unlink(inodePathTmp);
  436. }
  437.